﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Text;

namespace NOS.Common.ThreadSafe
{
    public class SafeHashTable
    {
        #region . Variables and Fields .

        private Hashtable Hash = null;
        private int AcessCount = 0;
        private int ReadWaiter = 0;
        private int ExclWaiter = 0;

        #endregion

        public SafeHashTable()
        {
            Trace.WriteLine("SafeHashTable : Creating Instance");
            Hash = new Hashtable();
            Trace.WriteLine("SafeHashTable: Instance criated");
        }

        public Hashtable GetExclusive()
        {
            Trace.WriteLine("SafeHashTable: Exclusive access required");
            lock (Hash)
            {
                ExclWaiter++;
                if (AcessCount != 0)
                {
                    Trace.WriteLine("SafeHashTable: Waiting for exclusive access");
                    Monitor.Wait(Hash);
                }
                ExclWaiter--;
                AcessCount = -1;
                Trace.WriteLine("SafeHashTable: Exclusive acess Allowed");
            }
            return Hash;
        }

        public Hashtable GetShared()
        {
            Trace.WriteLine("SafeHashTable: Shared access required");
            lock (Hash)
            {
                ReadWaiter++;
                if (AcessCount < 0 || ExclWaiter > 0)
                {
                    Trace.WriteLine("SafeHashTable: Waiting for Shared access");
                    Monitor.Wait(Hash);
                }
                ReadWaiter--;
                AcessCount++;
                Trace.WriteLine("SafeHashTable: Shared access Allowed");
            }
            return Hash;
        }

        public void ReleaseExclusive()
        {
            Trace.WriteLine("SafeHashTable: Realeasing exlusive");
            lock (Hash)
            {
                AcessCount = 0;
                if (ReadWaiter > 0)
                {
                    Trace.WriteLine("SafeHashTable: Readers waiting");
                    Monitor.PulseAll(Hash);
                }
                else
                {
                    Trace.WriteLine("SafeHashTable: Without readers waiting");
                    Monitor.Pulse(Hash);
                }
                Trace.WriteLine("SafeHashTable: Exclusive Access Released");
            }
        }

        public void ReleaseShared()
        {
            lock (Hash)
            {
                AcessCount--;
                if (AcessCount == 0)
                {
                    Monitor.Pulse(Hash);
                }
            }
        }
    }       
}
